/**
 * elancom Corporation copy right 2012 - 2015  
 *   
 * $Header: https://192.168.1.224/svn/elancom/product/elancom-platform/trunk/src/main/java/com/elancom/framework/commons/json/parser/deserializer/CollectionDeserializer.java 1034 2012-07-02 03:09:12Z lanzhouxue $
 * $Id: CollectionDeserializer.java 1034 2012-07-02 03:09:12Z lanzhouxue $
 * $Author: lanzhouxue $
 * $Date: 2012-07-02 11:09:12 +0800 (Mon, 02 Jul 2012) $
 * $Revision: 1034 $
 */
package com.elancom.framework.commons.json.parser.deserializer;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;

import com.elancom.framework.commons.json.JSONException;
import com.elancom.framework.commons.json.parser.DefaultJSONParser;
import com.elancom.framework.commons.json.parser.JSONToken;

public class CollectionDeserializer implements ObjectDeserializer {

	public final static CollectionDeserializer instance = new CollectionDeserializer();

	@Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
		if (parser.getLexer().token() == JSONToken.NULL) {
			parser.getLexer().nextToken(JSONToken.COMMA);
			return null;
		}

		final Class<?> rawClass = getRawClass(type);

		Collection list;
		if (rawClass == AbstractCollection.class) {
			list = new ArrayList();
		} else if (rawClass.isAssignableFrom(HashSet.class)) {
			list = new HashSet();
		} else if (rawClass.isAssignableFrom(LinkedHashSet.class)) {
			list = new LinkedHashSet();
		} else if (rawClass.isAssignableFrom(ArrayList.class)) {
			list = new ArrayList();
		} else {
			try {
				list = (Collection) rawClass.newInstance();
			} catch (final Exception e) {
				throw new JSONException("create instane error, class " + rawClass.getName());
			}
		}

		Type itemType;
		if (type instanceof ParameterizedType) {
			itemType = ((ParameterizedType) type).getActualTypeArguments()[0];
		} else {
			itemType = Object.class;
		}
		parser.parseArray(itemType, list, fieldName);

		return (T) list;
	}

	public Class<?> getRawClass(Type type) {

		if (type instanceof Class<?>) {
			return (Class<?>) type;
		} else if (type instanceof ParameterizedType) {
			return getRawClass(((ParameterizedType) type).getRawType());
		} else {
			throw new JSONException("TODO");
		}
	}

	@Override
	public int getFastMatchToken() {
		return JSONToken.LBRACKET;
	}
}
